home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / slip / cslip-2.6 / tip / cmds.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-09  |  16.6 KB  |  878 lines

  1. /*
  2.  * Copyright (c) 1983 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that: (1) source distributions retain this entire copyright
  7.  * notice and comment, and (2) distributions including binaries display
  8.  * the following acknowledgement:  ``This product includes software
  9.  * developed by the University of California, Berkeley and its contributors''
  10.  * in the documentation or other materials provided with the distribution
  11.  * and in all advertising materials mentioning features or use of this
  12.  * software. Neither the name of the University nor the names of its
  13.  * contributors may be used to endorse or promote products derived
  14.  * from this software without specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  */
  19.  
  20. #ifndef lint
  21. static char sccsid[] = "@(#)cmds.c    5.8 (Berkeley) 9/2/88";
  22. #endif /* not lint */
  23.  
  24. #include "tip.h"
  25. /*
  26.  * tip
  27.  *
  28.  * miscellaneous commands
  29.  */
  30.  
  31. int    quant[] = { 60, 60, 24 };
  32.  
  33. char    null = '\0';
  34. char    *sep[] = { "second", "minute", "hour" };
  35. static char *argv[10];        /* argument vector for take and put */
  36.  
  37. sigfunc_t    timeout();    /* timeout function called on alarm */
  38. sigfunc_t    stopsnd();    /* SIGINT handler during file transfers */
  39. sigfunc_t    intprompt();    /* used in handling SIG_INT during prompt */
  40. sigfunc_t    intcopy();    /* interrupt routine for file transfers */
  41.  
  42. /*
  43.  * FTP - remote ==> local
  44.  *  get a file from the remote host
  45.  */
  46. getfl(c)
  47.     char c;
  48. {
  49.     char buf[256], *cp, *expand();
  50.     
  51.     putchar(c);
  52.     /*
  53.      * get the UNIX receiving file's name
  54.      */
  55.     if (prompt("Local file name? ", copyname))
  56.         return;
  57.     cp = expand(copyname);
  58.     if ((sfd = creat(cp, 0666)) < 0) {
  59.         printf("\r\n%s: cannot creat\r\n", copyname);
  60.         return;
  61.     }
  62.     
  63.     /*
  64.      * collect parameters
  65.      */
  66.     if (prompt("List command for remote system? ", buf)) {
  67.         unlink(copyname);
  68.         return;
  69.     }
  70.     transfer(buf, sfd, value(EOFREAD));
  71. }
  72.  
  73. /*
  74.  * Cu-like take command
  75.  */
  76. cu_take(cc)
  77.     char cc;
  78. {
  79.     int fd, argc;
  80.     char line[BUFSIZ], *expand(), *cp;
  81.  
  82.     if (prompt("[take] ", copyname))
  83.         return;
  84.     if ((argc = args(copyname, argv)) < 1 || argc > 2) {
  85.         printf("usage: <take> from [to]\r\n");
  86.         return;
  87.     }
  88.     if (argc == 1)
  89.         argv[1] = argv[0];
  90.     cp = expand(argv[1]);
  91.     if ((fd = creat(cp, 0666)) < 0) {
  92.         printf("\r\n%s: cannot create\r\n", argv[1]);
  93.         return;
  94.     }
  95.     sprintf(line, "cat %s;echo \01", argv[0]);
  96.     transfer(line, fd, "\01");
  97. }
  98.  
  99. static    jmp_buf intbuf;
  100. /*
  101.  * Bulk transfer routine --
  102.  *  used by getfl(), cu_take(), and pipefile()
  103.  */
  104. transfer(buf, fd, eofchars)
  105.     char *buf, *eofchars;
  106. {
  107.     register int ct;
  108.     char c, buffer[BUFSIZ];
  109.     register char *p = buffer;
  110.     register int cnt, eof;
  111.     time_t start;
  112.     sigfunc_t (*f)();
  113.  
  114.     pwrite(FD, buf, size(buf));
  115.     quit = 0;
  116.     kill(pid, SIGIOT);
  117.     read(repdes[0], (char *)&ccc, 1);  /* Wait until read process stops */
  118.     
  119.     /*
  120.      * finish command
  121.      */
  122.     pwrite(FD, "\r", 1);
  123.     do
  124.         read(FD, &c, 1); 
  125.     while ((c&0177) != '\n');
  126.     ioctl(0, TIOCSETC, &defchars);
  127.     
  128.     (void) setjmp(intbuf);
  129.     f = signal(SIGINT, intcopy);
  130.     start = time(0);
  131.     for (ct = 0; !quit;) {
  132.         eof = read(FD, &c, 1) <= 0;
  133.         c &= 0177;
  134.         if (quit)
  135.             continue;
  136.           if (eof || any(c, eofchars))
  137.               break;
  138.         if (c == 0)
  139.             continue;    /* ignore nulls */
  140.         if (c == '\r')
  141.             continue;
  142.         *p++ = c;
  143.  
  144.         if (c == '\n' && boolean(value(VERBOSE)))
  145.             printf("\r%d", ++ct);
  146.         if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) {
  147.             if (write(fd, buffer, cnt) != cnt) {
  148.                 printf("\r\nwrite error\r\n");
  149.                 quit = 1;
  150.             }
  151.             p = buffer;
  152.         }
  153.     }
  154.     if (cnt = (p-buffer))
  155.         if (write(fd, buffer, cnt) != cnt)
  156.             printf("\r\nwrite error\r\n");
  157.  
  158.     if (boolean(value(VERBOSE)))
  159.         prtime(" lines transferred in ", time(0)-start);
  160.     ioctl(0, TIOCSETC, &tchars);
  161.     write(fildes[1], (char *)&ccc, 1);
  162.     signal(SIGINT, f);
  163.     close(fd);
  164. }
  165.  
  166. /*
  167.  * FTP - remote ==> local process
  168.  *   send remote input to local process via pipe
  169.  */
  170. pipefile()
  171. {
  172.     int cpid, pdes[2];
  173.     char buf[256];
  174.     int status, p;
  175.     extern int errno;
  176.  
  177.     if (prompt("Local command? ", buf))
  178.         return;
  179.  
  180.     if (pipe(pdes)) {
  181.         printf("can't establish pipe\r\n");
  182.         return;
  183.     }
  184.  
  185.     if ((cpid = fork()) < 0) {
  186.         printf("can't fork!\r\n");
  187.         return;
  188.     } else if (cpid) {
  189.         if (prompt("List command for remote system? ", buf)) {
  190.             close(pdes[0]), close(pdes[1]);
  191.             kill (cpid, SIGKILL);
  192.         } else {
  193.             sigfunc_t (*f)();
  194.  
  195.             close(pdes[0]);
  196.             f = signal(SIGPIPE, intcopy);
  197.             transfer(buf, pdes[1], value(EOFREAD));
  198.             signal(SIGPIPE, f);
  199.             while ((p = wait(&status)) > 0 && p != cpid)
  200.                 ;
  201.         }
  202.     } else {
  203.         register int f;
  204.  
  205.         dup2(pdes[0], 0);
  206.         close(pdes[0]);
  207.         for (f = 3; f < 20; f++)
  208.             close(f);
  209.         execute(buf);
  210.         printf("can't execl!\r\n");
  211.         exit(0);
  212.     }
  213. }
  214.  
  215. /*
  216.  * Interrupt service routine for FTP
  217.  */
  218. sigfunc_t
  219. stopsnd()
  220. {
  221.  
  222.     stop = 1;
  223.     signal(SIGINT, SIG_IGN);
  224. }
  225.  
  226. /*
  227.  * FTP - local ==> remote
  228.  *  send local file to remote host
  229.  *  terminate transmission with pseudo EOF sequence
  230.  */
  231. sendfile(cc)
  232.     char cc;
  233. {
  234.     FILE *fd;
  235.     char *fnamex;
  236.     char *expand();
  237.  
  238.     putchar(cc);
  239.     /*
  240.      * get file name
  241.      */
  242.     if (prompt("Local file name? ", fname))
  243.         return;
  244.  
  245.     /*
  246.      * look up file
  247.      */
  248.     fnamex = expand(fname);
  249.     if ((fd = fopen(fnamex, "r")) == NULL) {
  250.         printf("%s: cannot open\r\n", fname);
  251.         return;
  252.     }
  253.     transmit(fd, value(EOFWRITE), NULL);
  254.     if (!boolean(value(ECHOCHECK)) || boolean(value(LINESYNC))) {
  255.         struct sgttyb buf;
  256.  
  257.         ioctl(FD, TIOCGETP, &buf);    /* this does a */
  258.         ioctl(FD, TIOCSETP, &buf);    /*   wflushtty */
  259.     }
  260. }
  261.  
  262. /*
  263.  * Bulk transfer routine to remote host --
  264.  *   used by sendfile() and cu_put()
  265.  */
  266. transmit(fd, eofchars, command)
  267.     FILE *fd;
  268.     char *eofchars, *command;
  269. {
  270.     char *pc, lastc;
  271.     int c, ccount, lcount;
  272.     time_t start_t, stop_t;
  273.     sigfunc_t (*f)();
  274.  
  275.     kill(pid, SIGIOT);    /* put TIPOUT into a wait state */
  276.     stop = 0;
  277.     f = signal(SIGINT, stopsnd);
  278.     ioctl(0, TIOCSETC, &defchars);
  279.     read(repdes[0], (char *)&ccc, 1);
  280.     if (command != NULL) {
  281.         for (pc = command; *pc; pc++)
  282.             send(*pc);
  283.         if (boolean(value(ECHOCHECK)) || boolean(value(LINESYNC)))
  284.             read(FD, (char *)&c, 1);    /* trailing \n */
  285.         else {
  286.             struct sgttyb buf;
  287.  
  288.             ioctl(FD, TIOCGETP, &buf);    /* this does a */
  289.             ioctl(FD, TIOCSETP, &buf);    /*   wflushtty */
  290.             sleep(5); /* wait for remote stty to take effect */
  291.         }
  292.     }
  293.     lcount = 0;
  294.     lastc = '\0';
  295.     start_t = time(0);
  296.     while (1) {
  297.         ccount = 0;
  298.         do {
  299.             c = getc(fd);
  300.             if (stop)
  301.                 goto out;
  302.             if (c == EOF)
  303.                 goto out;
  304.             if (c == 0177 && !boolean(value(RAWFTP)))
  305.                 continue;
  306.             lastc = c;
  307.             if (c < 040) {
  308.                 if (c == '\n') {
  309.                     if (!boolean(value(RAWFTP)))
  310.                         c = '\r';
  311.                 }
  312.                 else if (c == '\t') {
  313.                     if (!boolean(value(RAWFTP))) {
  314.                         if (boolean(value(TABEXPAND))) {
  315.                             send(' ');
  316.                             while ((++ccount % 8) != 0)
  317.                                 send(' ');
  318.                             continue;
  319.                         }
  320.                     }
  321.                 } else
  322.                     if (!boolean(value(RAWFTP)))
  323.                         continue;
  324.             }
  325.             send(c);
  326.         } while (c != '\r' && !boolean(value(RAWFTP)));
  327.         if (boolean(value(VERBOSE)))
  328.             printf("\r%d", ++lcount);
  329.         if (boolean(value(ECHOCHECK)) || boolean(value(LINESYNC))) {
  330.             timedout = 0;
  331.             alarm(value(ETIMEOUT));
  332.             do {    /* wait for prompt */
  333.                 read(FD, (char *)&c, 1);
  334.                 if (timedout || stop) {
  335.                     if (timedout)
  336.                         printf("\r\ntimed out at eol\r\n");
  337.                     alarm(0);
  338.                     goto out;
  339.                 }
  340.             } while ((c&0177) != character(value(PROMPT)));
  341.             alarm(0);
  342.         }
  343.     }
  344. out:
  345.     if (lastc != '\n' && !boolean(value(RAWFTP)))
  346.         send('\r');
  347.     for (pc = eofchars; *pc; pc++)
  348.         send(*pc);
  349.     stop_t = time(0);
  350.     fclose(fd);
  351.     signal(SIGINT, f);
  352.     if (boolean(value(VERBOSE)))
  353.         if (boolean(value(RAWFTP)))
  354.             prtime(" chars transferred in ", stop_t-start_t);
  355.         else
  356.             prtime(" lines transferred in ", stop_t-start_t);
  357.     write(fildes[1], (char *)&ccc, 1);
  358.     ioctl(0, TIOCSETC, &tchars);
  359. }
  360.  
  361. /*
  362.  * Cu-like put command
  363.  */
  364. cu_put(cc)
  365.     char cc;
  366. {
  367.     FILE *fd;
  368.     char line[BUFSIZ];
  369.     int argc;
  370.     char *expand();
  371.     char *copynamex;
  372.  
  373.     if (prompt("[put] ", copyname))
  374.         return;
  375.     if ((argc = args(copyname, argv)) < 1 || argc > 2) {
  376.         printf("usage: <put> from [to]\r\n");
  377.         return;
  378.     }
  379.     if (argc == 1)
  380.         argv[1] = argv[0];
  381.     copynamex = expand(argv[0]);
  382.     if ((fd = fopen(copynamex, "r")) == NULL) {
  383.         printf("%s: cannot open\r\n", copynamex);
  384.         return;
  385.     }
  386.     if (boolean(value(ECHOCHECK)))
  387.         sprintf(line, "cat>%s\r", argv[1]);
  388.     else
  389.         sprintf(line, "stty -echo;cat>%s;stty echo\r", argv[1]);
  390.     transmit(fd, "\04", line);
  391. }
  392.  
  393. /*
  394.  * FTP - send single character
  395.  *  wait for echo & handle timeout
  396.  */
  397. send(c)
  398.     char c;
  399. {
  400.     char cc;
  401.     int retry = 0;
  402.  
  403.     cc = c;
  404.     pwrite(FD, &cc, 1);
  405. #ifdef notdef
  406.     if (number(value(CDELAY)) > 0 && c != '\r')
  407.         nap(number(value(CDELAY)));
  408. #endif
  409.     if (!boolean(value(ECHOCHECK))) {
  410. #ifdef notdef
  411.         if (number(value(LDELAY)) > 0 && c == '\r')
  412.             nap(number(value(LDELAY)));
  413. #endif
  414.         return;
  415.     }
  416. tryagain:
  417.     timedout = 0;
  418.     alarm(value(ETIMEOUT));
  419.     read(FD, &cc, 1);
  420.     alarm(0);
  421.     if (timedout) {
  422.         printf("\r\ntimeout error (%s)\r\n", ctrl(c));
  423.         if (retry++ > 3)
  424.             return;
  425.         pwrite(FD, &null, 1); /* poke it */
  426.         goto tryagain;
  427.     }
  428. }
  429.  
  430. sigfunc_t
  431. timeout()
  432. {
  433.     signal(SIGALRM, timeout);
  434.     timedout = 1;
  435. }
  436.  
  437. /*
  438.  * Stolen from consh() -- puts a remote file on the output of a local command.
  439.  *    Identical to consh() except for where stdout goes.
  440.  */
  441. pipeout(c)
  442. {
  443.     char buf[256];
  444.     int cpid, status, p;
  445.     time_t start;
  446.  
  447.     putchar(c);
  448.     if (prompt("Local command? ", buf))
  449.         return;
  450.     kill(pid, SIGIOT);    /* put TIPOUT into a wait state */
  451.     signal(SIGINT, SIG_IGN);
  452.     signal(SIGQUIT, SIG_IGN);
  453.     ioctl(0, TIOCSETC, &defchars);
  454.     read(repdes[0], (char *)&ccc, 1);
  455.     /*
  456.      * Set up file descriptors in the child and
  457.      *  let it go...
  458.      */
  459.     if ((cpid = fork()) < 0)
  460.         printf("can't fork!\r\n");
  461.     else if (cpid) {
  462.         start = time(0);
  463.         while ((p = wait(&status)) > 0 && p != cpid)
  464.             ;
  465.     } else {
  466.         register int i;
  467.  
  468.         dup2(FD, 1);
  469.         for (i = 3; i < 20; i++)
  470.             close(i);
  471.         signal(SIGINT, SIG_DFL);
  472.         signal(SIGQUIT, SIG_DFL);
  473.         execute(buf);
  474.         printf("can't find `%s'\r\n", buf);
  475.         exit(0);
  476.     }
  477.     if (boolean(value(VERBOSE)))
  478.         prtime("away for ", time(0)-start);
  479.     write(fildes[1], (char *)&ccc, 1);
  480.     ioctl(0, TIOCSETC, &tchars);
  481.     signal(SIGINT, SIG_DFL);
  482.     signal(SIGQUIT, SIG_DFL);
  483. }
  484.  
  485. #ifdef CONNECT
  486. /*
  487.  * Fork a program with:
  488.  *  0 <-> local tty in
  489.  *  1 <-> local tty out
  490.  *  2 <-> local tty out
  491.  *  3 <-> remote tty in
  492.  *  4 <-> remote tty out
  493.  */
  494. consh(c)
  495. {
  496.     char buf[256];
  497.     int cpid, status, p;
  498.     time_t start;
  499.  
  500.     putchar(c);
  501.     if (prompt("Local command? ", buf))
  502.         return;
  503.     kill(pid, SIGIOT);    /* put TIPOUT into a wait state */
  504.     signal(SIGINT, SIG_IGN);
  505.     signal(SIGQUIT, SIG_IGN);
  506.     ioctl(0, TIOCSETC, &defchars);
  507.     read(repdes[0], (char *)&ccc, 1);
  508.     /*
  509.      * Set up file descriptors in the child and
  510.      *  let it go...
  511.      */
  512.     if ((cpid = fork()) < 0)
  513.         printf("can't fork!\r\n");
  514.     else if (cpid) {
  515.         start = time(0);
  516.         while ((p = wait(&status)) > 0 && p != cpid)
  517.             ;
  518.     } else {
  519.         register int i;
  520.  
  521.         dup2(FD, 3);
  522.         dup2(3, 4);
  523.         for (i = 5; i < 20; i++)
  524.             close(i);
  525.         signal(SIGINT, SIG_DFL);
  526.         signal(SIGQUIT, SIG_DFL);
  527.         execute(buf);
  528.         printf("can't find `%s'\r\n", buf);
  529.         exit(0);
  530.     }
  531.     if (boolean(value(VERBOSE)))
  532.         prtime("away for ", time(0)-start);
  533.     write(fildes[1], (char *)&ccc, 1);
  534.     ioctl(0, TIOCSETC, &tchars);
  535.     signal(SIGINT, SIG_DFL);
  536.     signal(SIGQUIT, SIG_DFL);
  537. }
  538. #endif
  539.  
  540. /*
  541.  * Escape to local shell
  542.  */
  543. shell()
  544. {
  545.     int shpid, status;
  546.     extern char **environ;
  547.     char *cp;
  548.  
  549.     printf("[sh]\r\n");
  550.     signal(SIGINT, SIG_IGN);
  551.     signal(SIGQUIT, SIG_IGN);
  552.     unraw();
  553.     if (shpid = fork()) {
  554.         while (shpid != wait(&status));
  555.         raw();
  556.         printf("\r\n!\r\n");
  557.         signal(SIGINT, SIG_DFL);
  558.         signal(SIGQUIT, SIG_DFL);
  559.         return;
  560.     } else {
  561.         signal(SIGQUIT, SIG_DFL);
  562.         signal(SIGINT, SIG_DFL);
  563.         if ((cp = rindex(value(SHELL), '/')) == NULL)
  564.             cp = value(SHELL);
  565.         else
  566.             cp++;
  567.         shell_uid();
  568.         execl(value(SHELL), cp, 0);
  569.         printf("\r\ncan't execl!\r\n");
  570.         exit(1);
  571.     }
  572. }
  573.  
  574. /*
  575.  * TIPIN portion of scripting
  576.  *   initiate the conversation with TIPOUT
  577.  */
  578. setscript()
  579. {
  580.     char c;
  581.     /*
  582.      * enable TIPOUT side for dialogue
  583.      */
  584.     kill(pid, SIGEMT);
  585.     if (boolean(value(SCRIPT)))
  586.         write(fildes[1], value(RECORD), size(value(RECORD)));
  587.     write(fildes[1], "\n", 1);
  588.     /*
  589.      * wait for TIPOUT to finish
  590.      */
  591.     read(repdes[0], &c, 1);
  592.     if (c == 'n')
  593.         printf("can't create %s\r\n", value(RECORD));
  594. }
  595.  
  596. /*
  597.  * Change current working directory of
  598.  *   local portion of tip
  599.  */
  600. chdirectory()
  601. {
  602.     char dirname[80];
  603.     register char *cp = dirname;
  604.  
  605.     if (prompt("[cd] ", dirname)) {
  606.         if (stoprompt)
  607.             return;
  608.         cp = value(HOME);
  609.     }
  610.     if (chdir(cp) < 0)
  611.         printf("%s: bad directory\r\n", cp);
  612.     printf("!\r\n");
  613. }
  614.  
  615. abort(msg)
  616.     char *msg;
  617. {
  618.  
  619.     if (pid)
  620.         kill(pid, SIGTERM);
  621.     disconnect(msg);
  622.     if (msg != NOSTR)
  623.         printf("\r\n%s", msg);
  624.     printf("\r\n[EOT]\r\n");
  625.     daemon_uid();
  626.     (void)uu_unlock(uucplock);
  627.     unraw();
  628.     exit(0);
  629. }
  630.  
  631. finish()
  632. {
  633.     char *dismsg;
  634.  
  635.     if ((dismsg = value(DISCONNECT)) != NOSTR) {
  636.         write(FD, dismsg, strlen(dismsg));
  637.         sleep(5);
  638.     }
  639.     abort(NOSTR);
  640. }
  641.  
  642. sigfunc_t
  643. intcopy()
  644. {
  645.  
  646.     raw();
  647.     quit = 1;
  648.     longjmp(intbuf, 1);
  649. }
  650.  
  651. execute(s)
  652.     char *s;
  653. {
  654.     register char *cp;
  655.  
  656.     if ((cp = rindex(value(SHELL), '/')) == NULL)
  657.         cp = value(SHELL);
  658.     else
  659.         cp++;
  660.     user_uid();
  661.     execl(value(SHELL), cp, "-c", s, 0);
  662. }
  663.  
  664. args(buf, a)
  665.     char *buf, *a[];
  666. {
  667.     register char *p = buf, *start;
  668.     register char **parg = a;
  669.     register int n = 0;
  670.  
  671.     do {
  672.         while (*p && (*p == ' ' || *p == '\t'))
  673.             p++;
  674.         start = p;
  675.         if (*p)
  676.             *parg = p;
  677.         while (*p && (*p != ' ' && *p != '\t'))
  678.             p++;
  679.         if (p != start)
  680.             parg++, n++;
  681.         if (*p)
  682.             *p++ = '\0';
  683.     } while (*p);
  684.  
  685.     return(n);
  686. }
  687.  
  688. prtime(s, a)
  689.     char *s;
  690.     time_t a;
  691. {
  692.     register i;
  693.     int nums[3];
  694.  
  695.     for (i = 0; i < 3; i++) {
  696.         nums[i] = (int)(a % quant[i]);
  697.         a /= quant[i];
  698.     }
  699.     printf("%s", s);
  700.     while (--i >= 0)
  701.         if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0)
  702.             printf("%d %s%c ", nums[i], sep[i],
  703.                 nums[i] == 1 ? '\0' : 's');
  704.     printf("\r\n!\r\n");
  705. }
  706.  
  707. variable()
  708. {
  709.     char    buf[256];
  710.  
  711.     if (prompt("[set] ", buf))
  712.         return;
  713.     vlex(buf);
  714.     if (vtable[BEAUTIFY].v_access&CHANGED) {
  715.         vtable[BEAUTIFY].v_access &= ~CHANGED;
  716.         kill(pid, SIGSYS);
  717.     }
  718.     if (vtable[SCRIPT].v_access&CHANGED) {
  719.         vtable[SCRIPT].v_access &= ~CHANGED;
  720.         setscript();
  721.         /*
  722.          * So that "set record=blah script" doesn't
  723.          *  cause two transactions to occur.
  724.          */
  725.         if (vtable[RECORD].v_access&CHANGED)
  726.             vtable[RECORD].v_access &= ~CHANGED;
  727.     }
  728.     if (vtable[RECORD].v_access&CHANGED) {
  729.         vtable[RECORD].v_access &= ~CHANGED;
  730.         if (boolean(value(SCRIPT)))
  731.             setscript();
  732.     }
  733.     if (vtable[TAND].v_access&CHANGED) {
  734.         vtable[TAND].v_access &= ~CHANGED;
  735.         if (boolean(value(TAND)))
  736.             tandem("on");
  737.         else
  738.             tandem("off");
  739.     }
  740.      if (vtable[LECHO].v_access&CHANGED) {
  741.          vtable[LECHO].v_access &= ~CHANGED;
  742.          HD = boolean(value(LECHO));
  743.      }
  744.     if (vtable[PARITY].v_access&CHANGED) {
  745.         vtable[PARITY].v_access &= ~CHANGED;
  746.         setparity();
  747.     }
  748. }
  749.  
  750. /*
  751.  * Turn tandem mode on or off for remote tty.
  752.  */
  753. tandem(option)
  754.     char *option;
  755. {
  756.     struct sgttyb rmtty;
  757.  
  758.     ioctl(FD, TIOCGETP, &rmtty);
  759.     if (strcmp(option,"on") == 0) {
  760.         rmtty.sg_flags |= TANDEM;
  761.         arg.sg_flags |= TANDEM;
  762.     } else {
  763.         rmtty.sg_flags &= ~TANDEM;
  764.         arg.sg_flags &= ~TANDEM;
  765.     }
  766.     ioctl(FD, TIOCSETP, &rmtty);
  767.     ioctl(0,  TIOCSETP, &arg);
  768. }
  769.  
  770. /*
  771.  * Send a break.
  772.  */
  773. genbrk()
  774. {
  775.  
  776.     ioctl(FD, TIOCSBRK, NULL);
  777.     sleep(1);
  778.     ioctl(FD, TIOCCBRK, NULL);
  779. }
  780.  
  781. /*
  782.  * Suspend tip
  783.  */
  784. suspend(c)
  785.     char c;
  786. {
  787.  
  788.     unraw();
  789.     kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
  790.     raw();
  791. }
  792.  
  793. /*
  794.  *    expand a file name if it includes shell meta characters
  795.  */
  796.  
  797. char *
  798. expand(name)
  799.     char name[];
  800. {
  801.     static char xname[BUFSIZ];
  802.     char cmdbuf[BUFSIZ];
  803.     register int pid, l;
  804.     register char *cp, *Shell;
  805.     int s, pivec[2], (*sigint)();
  806.  
  807.     if (!anyof(name, "~{[*?$`'\"\\"))
  808.         return(name);
  809.     /* sigint = signal(SIGINT, SIG_IGN); */
  810.     if (pipe(pivec) < 0) {
  811.         perror("pipe");
  812.         /* signal(SIGINT, sigint) */
  813.         return(name);
  814.     }
  815.     sprintf(cmdbuf, "echo %s", name);
  816.     if ((pid = vfork()) == 0) {
  817.         Shell = value(SHELL);
  818.         if (Shell == NOSTR)
  819.             Shell = "/bin/sh";
  820.         close(pivec[0]);
  821.         close(1);
  822.         dup(pivec[1]);
  823.         close(pivec[1]);
  824.         close(2);
  825.         shell_uid();
  826.         execl(Shell, Shell, "-c", cmdbuf, 0);
  827.         _exit(1);
  828.     }
  829.     if (pid == -1) {
  830.         perror("fork");
  831.         close(pivec[0]);
  832.         close(pivec[1]);
  833.         return(NOSTR);
  834.     }
  835.     close(pivec[1]);
  836.     l = read(pivec[0], xname, BUFSIZ);
  837.     close(pivec[0]);
  838.     while (wait(&s) != pid);
  839.         ;
  840.     s &= 0377;
  841.     if (s != 0 && s != SIGPIPE) {
  842.         fprintf(stderr, "\"Echo\" failed\n");
  843.         return(NOSTR);
  844.     }
  845.     if (l < 0) {
  846.         perror("read");
  847.         return(NOSTR);
  848.     }
  849.     if (l == 0) {
  850.         fprintf(stderr, "\"%s\": No match\n", name);
  851.         return(NOSTR);
  852.     }
  853.     if (l == BUFSIZ) {
  854.         fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
  855.         return(NOSTR);
  856.     }
  857.     xname[l] = 0;
  858.     for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
  859.         ;
  860.     *++cp = '\0';
  861.     return(xname);
  862. }
  863.  
  864. /*
  865.  * Are any of the characters in the two strings the same?
  866.  */
  867.  
  868. anyof(s1, s2)
  869.     register char *s1, *s2;
  870. {
  871.     register int c;
  872.  
  873.     while (c = *s1++)
  874.         if (any(c, s2))
  875.             return(1);
  876.     return(0);
  877. }
  878.